/******************************************************************************
 * Copyright 2022 The AIR Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

#pragma once

#include <malloc.h>
#include <sys/types.h>

#include <cstddef>
#include <cstdint>
#include <string>

#ifndef ASN_MODULE_NAME
#error "ASN_MODULE_NAME is NOT defined"
#endif

#undef ASN_MODULE_EXTERN
#define ASN_MODULE_EXTERN __attribute__((visibility("default")))

#undef V2X_ASN_FUNC_NAME2
#define V2X_ASN_FUNC_NAME2(module_name, func_name) \
  v2x_asn_msg_##module_name##_##func_name

#undef V2X_ASN_FUNC_NAME2_HELPER
#define V2X_ASN_FUNC_NAME2_HELPER(module_name, func_name) \
  V2X_ASN_FUNC_NAME2(module_name, func_name)

#undef V2X_ASN_FUNC_NAME
#define V2X_ASN_FUNC_NAME(func_name) \
  V2X_ASN_FUNC_NAME2_HELPER(ASN_MODULE_NAME, func_name)

typedef void *(*malloc_func_t)(size_t);

#undef V2X_ASN_FUNC
#define V2X_ASN_FUNC(func_name)                                               \
  ssize_t V2X_ASN_FUNC_NAME(func_name)(const void *buffer, size_t buffer_len, \
                                       void **result,                         \
                                       malloc_func_t malloc_func)

#undef V2X_ASN_FUNC_DECL

#define V2X_ASN_FUNC_DECL(func_name)                                       \
  ASN_MODULE_EXTERN ssize_t V2X_ASN_FUNC_NAME(func_name)(                  \
      const void *buffer, size_t buffer_len, void **result,                \
      malloc_func_t malloc_func = nullptr);                                \
  extern "C++" {                                                           \
  inline ssize_t V2X_ASN_FUNC_NAME(func_name)(const void *buffer,          \
                                              size_t buffer_len,           \
                                              std::string *result_str) {   \
    void *result = nullptr;                                                \
    auto result_len =                                                      \
        V2X_ASN_FUNC_NAME(func_name)(buffer, buffer_len, &result, malloc); \
    if (result_len < 0) {                                                  \
      return result_len;                                                   \
    }                                                                      \
    *result_str = std::string((const char *)result, result_len);           \
    free(result);                                                          \
    return result_len;                                                     \
  }                                                                        \
  inline ssize_t V2X_ASN_FUNC_NAME(func_name)(const std::string &input,    \
                                              std::string *result_str) {   \
    return V2X_ASN_FUNC_NAME(func_name)(input.c_str(), input.length(),     \
                                        result_str);                       \
  }                                                                        \
  }

extern "C" {

enum {
  V2X_ASN_ERR_INTERNAL = INT16_MIN,
  V2X_ASN_ERR_INVALID_PARAM,
  V2X_ASN_ERR_UPER_DECODE,
  V2X_ASN_ERR_UPER_ENCODE,
  V2X_ASN_ERR_XER_DECODE,
  V2X_ASN_ERR_XER_ENCODE,
  V2X_ASN_ERR_NO_MEMORY,
  V2X_ASN_ERR_CONV,
  // LAST ONE
  V2X_ASN_ERR_EMPTY = 0,
};
}
